//参考文章https://blog.csdn.net/xp178171640/article/details/104570081/
#ifndef THREADPOOL_H
#define THREADPOOL_H

#include <thread>
#include <mutex>
#include <string>
#include <vector>
#include <deque>
#include <functional>
#include <condition_variable>
#include <iostream>

namespace linch {

class ThreadPool
{
public:
    //入参为空的任务类型
    typedef std::function<void()> Task;

    //设置任务队列上限
    void setMaxQueueSize(int maxSize) { m_maxQueueSize = maxSize; }
    //设置工作线程初始执行的回调函数
    void setThreadInitCallback(const Task& cb)
    {
        m_threadInitCallback = cb;
    }
    //开启指定数量的工作线程
    void start(int count);
    //退出线程池执行,退出所有的工作线程
    void stop();

    //获取线程池名字
    const std::string& getName() { return m_name; }
    //任务队列多少
    size_t getQueueSize() const;

    //新任务入队,若队列已满,将堵塞接口调用线程
    void run(const Task& func);
public:
    //explicit:禁止隐形转化
    explicit ThreadPool(const std::string&name = "ThreadPool");
    ~ThreadPool();
private:
    //禁止拷贝构造
    ThreadPool(const ThreadPool&) = delete;
    ThreadPool& operator=(const ThreadPool&) = delete;
    //判断队列是否已满
    bool isFull() const;
    //完成任务到线程的分发
    // 线程池对象维护了任务队列，工作线程在执行时需要从任务队列中获取工作任务，
    // 所以只能将线程的执行体与线程池对象的接口关联，完成工作任务获取；
    void runInThread();
    //从任务队列中去任务执行
    Task take();
private:
    //mutable,突破const的限制
    mutable std::mutex m_mutex;  //任务队列的互斥锁
    std::condition_variable m_notEmpty;  //当前队列为空的条件变量,工作线程取任务时,空则等待
    std::condition_variable m_notFull;  //队列已满的条件变量,任务入队时,已满则等待
    std::string m_name; //线程池名字
    Task m_threadInitCallback;  //工作线程初次执行的回调
    std::vector<std::thread*> m_threads; //工程线程集
    std::deque<Task> m_queue;   //任务队列
    size_t m_maxQueueSize;      //任务量上限
    bool m_runing;              //线程池是否在执行
};

}


#endif // THREADPOOL_H
